Http with iziBasic and PP
Thursday 26 October 2006 - 11:27:59
Yes i use now a lot ppcompiler, but i ven't forgotten iziBasic, the first language i ve used to create my own application. Here you will find an article about how to make http request with iziBasic and an pp applet.


Needed


  • PPShell
  • pp.exe for ARM
  • iziBasic
  • Knowledge about compilation with PP
  • Knowledge about compilation with iziBasic


The PP Applet (Pascal)

Two choices are avaible :

  • Return the result of the http request with the string response of the applet. But string are limited to 64 character.
  • Write the result of the http request in a palm file to use it entirely in iziBasic.

So we will see the second choice.


Here the source code of the applet.




program iBHttpPP;




//

type iBasFunType=function(S:string):string;

var iBasCallPP:iBasFunType;

const
MAXMEGASTRING=16376;
//PP limits arrays to 32 k ... this one is one of the biggest you can create
// soit MAXMEGASTRING=32752;

type
u_char=UInt8;
u_short=UInt16;
u_int=UInt16;
u_long=UInt32;
size_t=UInt32;

MegaStringPtr = ^MegaStringType;
MegaStringType = Array[0..MAXMEGASTRING] of char;

const
SOCK_STREAM=netSocketTypeStream;
SOCK_DGRAM=netSocketTypeDatagram;
SOCK_RAW=netSocketTypeRaw;
SOCK_RDM=netSocketTypeReliableMsg;
AF_INET=netSocketAddrINET;
AF_RAW=netSocketAddrRaw;

type

sockaddr=record
sa_family: Int16;
sa_data: array[1..14] of UInt8;
end;

in_addr=record
case integer of
1:( s_net, s_host, s_lh, s_impno: UInt8; );
2:( s_W1, s_imp: UInt16; );
3:( s_addr: UInt32 );
end;

sockaddr_in=record
sin_family: Int16;
sin_port: u_short;
sin_addr: in_addr;
sin_zero: array[1..8] of char;
end;

/////////////////////////////////////
// StringToRessourceLab
/////////////////////////////////////
function StringToRessourceLab(const sMyString:string):integer;
begin
StringToRessourceLab:=
Ord(sMyString[4])+
256*Ord(sMyString[3])+
65536*Ord(sMyString[2])+
16777216*Ord(sMyString[1]);
end;


/////////////////////////////////////
// charcpy
// procedure to copy a string in
// the megastring buffer
/////////////////////////////////////
procedure charcpy(var index:UInt16;c:MegaStringPtr;s:String);
var
i:UInt32;

begin
i:=1;
while (s[i]<>chr(0)) and (index
 c^[index]:=s[i];
 index:=index+1;
 i:=i+1;
end;

if index>MAXMEGASTRING then
 index:=MAXMEGASTRING;

end;
/////////////////////////////////////
// CreateDb
// Funtion to create a palm data database
/////////////////////////////////////
Function CreateDb(resName,resCreator,rType:string):Err;
var
CardNumber:integer;
DBErr:Err;
libCreatorID:Uint32;
IDDataBase:LocalID;

Begin
CardNumber:=0;
IDDataBase:=DmFindDatabase(0,resName);
if (IDDataBase=0) then
 DBErr := DmCreateDatabase(CardNumber, resName,StringToRessourceLab(resCreator),StringToRessourceLab(rType), false);
 CreateDb:=DBErr;
end;

/////////////////////////////////////
// DelDb
// Function to del a palm database
/////////////////////////////////////
Procedure DelDb(resName:string);
var
 CardNumber:integer;
 DBErr:Err;
 IDDataBase:localID;

Begin

 CardNumber:=0;
 IDDataBase:=DmFindDatabase(0,resName);
 if (IDDataBase>0) then
  DBErr := DmDeleteDatabase(CardNumber, IDDataBase);

end;

/////////////////////////////////////
// WriteHTTP
// Function to write the megastring
// buffer to a palm database
/////////////////////////////////////
procedure WriteHTTP(fichier:String;s:MegaStringPtr;size:UInt32);
var
 h:Memhandle;
 pp:Pointer;
 u:UInt16;
 e:Err;
 gDataBase:DmOpenRef;
 IDDataBase:LocalID;

begin
 IDDataBase:=DmFindDatabase(0,fichier);
 if (IDDataBase<>0) then Begin
  gDataBase:=DmOpenDatabase(0,IDDataBase,dmModeReadWrite);
  if (gDataBase<>nil) then begin
   if DmNumRecords(gDataBase)<65000 then begin
    u:=0; // new record
    h:=DmNewRecord(gDataBase,u,size);
    if h<>nil then begin
     pp:=MemHandleLock(h);
     if pp <> nil then begin
      DmWrite(pp,0,s,size);
      DmReleaseRecord(gDataBase,u,true);
      MemHandleUnlock(h); // PG 22022004
     end;
    end;
   end;
   DmCloseDatabase(gDataBase);
  end;
 end;
end;

/////////////////////////////////////
// getbyname
// The main function of the applet.
// Here is constructed the http
// request, sent, and after we read
// the answer to write it to a file
/////////////////////////////////////

function getbyname(fichier:string;domain:string;page:String;port:UInt16):String;
var
 size,received:UInt16;
 refsocket:NetSocketRef;
 address:NetSocketAddrType;
 address_in:NetSocketAddrINType;
 address_inaddrPtr:Pointer;
 host:NetHostInfoBufType;
 requetehttp:MegaStringPtr;
 indexrequetehttp:UInt16;
 endline:string;
 libRef:UInt16;
 error:UInt16;
 erreur:Err;
 y,nb:UInt16;
 AppNetTimeout: Int32;
 AppNetRefnum: UInt16;
 sent:UInt16;
 saved:WinHandle;

begin
 AppNetRefnum:=0;
 error:=0;
 //Recherche de la netlib
 SysLibFind('Net.lib',AppNetRefnum);
 //Set timeout
 AppNetTimeout:=30*100;
 //Init of the megastring buffer
 requetehttp:=MemPtrNew(sizeof(char)*MAXMEGASTRING);
 //Test if buffer is correctly initializing.
 if requetehttp=nil then begin
  error:=1;
  getbyname:='Error in memory allocating ...';
 end;

 //Si le buffer est bien initialise alors nous attaquons
 if error=0 then begin
  //Opening netlib
  erreur:=NetLibOpen(AppNetRefnum,error);//,error);

  //If it s ok ... so
  if (error=0) or (error=$1201) then begin
   //We ask the ip of the hostname to the dns.
   NetLibGetHostByName(AppNetRefnum, domain,@host,AppNetTimeout,error);
   //We forge the socket
   refsocket:=NetLibSocketOpen(AppNetRefnum,netSocketAddrINET,netSocketTypeStream,6,AppNetTimeout,error);
   if refsocket<>0 then begin
    address_in.addr:=host.address[0];
    address_in.family:= 2;
    address_in.port:=port;
    //Connecting socket
    error:=NetLibSocketConnect(AppNetRefnum,refsocket,@address_in,sizeof(address_in),AppNetTimeout,erreur);

    if erreur=0 then begin
    //Forge de la requete http
     endline:=CHR(13)+CHR(10);
     indexrequetehttp:=0;
     charcpy(indexrequetehttp,requetehttp,'GET '+page);
     charcpy(indexrequetehttp,requetehttp,' HTTP/1.1'+endline+'host: '+domain+endline);
     charcpy(indexrequetehttp,requetehttp,'Connection: close'+endline);
     charcpy(indexrequetehttp,requetehttp,'User-Agent: Palm'+endline); 
    charcpy(indexrequetehttp,requetehttp,endline); 
    //We send the request until all is sent or an error occur
    sent:=0;
    error:=1;
    while (sent0) and (erreur=0) do begin
     error:=NetLibSend(AppNetRefnum,refsocket,@requetehttp^[sent],indexrequetehttp-sent,0,nil,0,AppNetTimeout,erreur);
     sent:=sent+error;
    end;

    //if nothing is sent then error occurs
    if sent<=0 then getbyname:='Error while sending...';

    //We read answer in the netlib buffer until the buffer is clear
    error:=1;
    erreur:=0;
    sent:=0; 
    while (error>0) and ((MAXMEGASTRING-sent)>1) and (erreur=0) do begin
     error:=NetLibReceive(AppNetRefnum,refsocket,@requetehttp^[sent],(MAXMEGASTRING-sent),0,nil,nil,AppNetTimeout,erreur);
     sent:=sent+error;
    end;

    //We del the file
    DelDb(fichier);
    //We create a new palm database
    CreateDb(fichier,('Khrt'),('http'));
    //We write the result of the request
    WriteHTTP(fichier,requetehttp,sent);
   end else begin
    getbyname:='Can t open socket';
   end;
   NetLibSocketClose(AppNetRefnum, refsocket,AppNetTimeout,erreur);
  end else begin
   getbyname:='Can t create socket';
  end;
  NetLibClose(AppNetRefnum,0);
 end else begin
  getbyname:='Can t open netlib';
 end;
end;

MemPtrFree(requetehttp);
end;


//Fonction appele par iziBasic lors d un CallPP
function CallPP(S:string):string;
var
 url,fichier,domain,page,port:String;
 i,u:UInt16;

begin
 url:='';
 fichier:='';
 domain:='';
 page:=''; 
 port:='';
 i:=1; 
 u:=0;

 //Tokenize of the iziBasic call parameter string
 // le fichier
 // le domaine
 // la page 
 // le port
 while (S[i]<>CHR(0)) and (i<=64) do begin
  if (S[i]<>CHR(10)) then begin
   case u of
    0: begin fichier:=fichier+S[i]; end;
    1: begin url:=url+S[i]; end;
    2: begin port:=port+S[i]; end;
  end;
  end else begin
  u:=u+1;
 end;
 i:=i+1;
 end;


 i:=1;
 u:=0;
 while (url[i]<>CHR(0)) and (i<=64) do begin
  if (url[i]<>'/') then begin
   if u=0 then begin
    domain:=domain+url[i];
   end else begin
    page:=page+url[i];
   end;
  end else begin
   u:=1;
   page:=page+url[i];
  end;

  i:=i+1;
 end;
 CallPP:=getbyname(fichier,domain,page,StrAToI(port));
// CallPP:=port;
end;

begin
 iBasCallPP:=CallPP;
end.


Nothing is difficult, only an access to an api we can't reach with iziBasic.

For more information about the netlib connection read my other paper about pp and socket.


The iziBasic code Now i ll show you how to use our applet.


' iBHttpPP.ibas



BEGIN
LABEL #1,"Fichier : TESTHTTP",2,30
LABEL #2,"URL : khertan.net/index.php",2,40
LABEL #3,"Port : 80",2,50

REM The parameter string
REM The file (here : TESTHTTP)
REM CHR$(10)
REM URL (here : khertan.net/index.php)
REM CHR$(10)
REM The port : (here : 80)

R$="TESTHTTP"+CHR$(10)+"khertan.net/index.php"+CHR$(10)+"80"
A$=CALLPP$(100,R$)

A=FILEERROR
IF A=0 THEN
 A$="PP Code replied: '"+A$+"'"
ELSE
 A$="PP Code was not found!"
ENDIF

LABEL #4,A$,2,80

REPEAT : A=DOEVENTS : UNTIL A=-1
END


Conclusion
Now all is possible ...



Khertan.net by Benoit HERVIER Alias Khertan.